#pragma once

namespace col {

static wxString empty_string;

struct is_empty : public std::unary_function < wxString, bool >
{
	bool operator() ( const wxString &str ) const 
	{ 
		return str.empty();
	}
};

struct append_if
{
	template < typename unaryfunc >
	append_if ( wxString &to, const wxString &what, unaryfunc func )
	{
		if ( func ( to ) ) to += what;
	}
};

//! Capitalizes the string.
void capitalize ( wxString &str );

//! Capitalizes the string and returns the result.
const wxString capitalize ( const wxString &str );

/*! @brief Compresses the given file.
 *
 * Compresses a file with zlib.
 *
 * @param infile Path to the file that will be compressed.
 * @param outfile Path to the compressed file.
 * @param level The used compression level (1-9).
 * @return true on success, false otherwise.
 **/
bool compress_file ( const wxString &infile, const wxString &outfile, wxUint32 level );

/*! @brief Decompresses the given file.
 * 
 * Decompresses a file that has been compressed with zlib.
 *
 * @param infile Path to the file that will be decompressed.
 * @param outfile Path to the decompressed file.
 * @return true on success, false otherwise.
 **/
bool decompress_file ( const wxString &infile, const wxString &outfile );

//! A (simple) function for downloading a webpage.
void get_webpage ( const wxURI &rUri, wxString &rTo, wxUint32 timeout = 100,
				  wxUint32 port = 80 );

const wxString protocol_err_to_str ( wxProtocolError err, const wxURI &rUri );

//! An abstract tree adapter base class. 
template < typename node_type >
struct tree_adapter
{
	//! Returns the content of the node or an empty string on error.
	virtual const wxString get_content ( node_type n ) const = 0;
	//! Returns the parent node of n or invalid_node() on error.
	virtual node_type get_parent ( node_type n ) const = 0; 
	//! Returns the first child item of n or invalid_node() on error.
	virtual node_type get_first_child ( node_type n ) = 0;
	//! Returns the next sibling of n or invalid_node() on error.
	virtual node_type get_next_sibling ( node_type n ) const = 0;
	//! Returns true if the node is ok (i.e. valid) or false otherwise.
	virtual bool is_ok ( node_type n ) const = 0;
	//! Returns true if the two nodes are the same (i.e. they point to the same node).
	virtual bool is_same_as ( node_type n1, node_type n2 ) const = 0;
	//! Compares the node to the string 'str' and returns true if they are equal or false otherise.
	virtual bool compare ( node_type n, const wxString &str ) const = 0;
	//! Returns an invalid node for the node_type (e.g. null pointer).
	virtual node_type invalid_node() const = 0;
};

//! A tree adapther for the wxXmlNode class.
template < typename node_type = const wxXmlNode * >
class wxxml_tree_adapter : public tree_adapter < node_type >
{
public:
	const wxString get_content ( node_type n ) const 
	{
		return n ? n->GetNodeContent() : empty_string;
	}
	node_type get_parent ( node_type n ) const 
	{
		return n ? n->GetParent() : invalid_node();
	}
	node_type get_first_child ( node_type n ) 
	{
		return n ? n->GetChildren() : invalid_node();
	}
	node_type get_next_sibling ( node_type n ) const 
	{
		return n ? n->GetNext() : invalid_node();
	}
	bool is_ok ( node_type n ) const 
	{
		return n != invalid_node();
	}
	bool is_same_as ( node_type n1, node_type n2 ) const 
	{
		return get_name ( n1 ) == get_name ( n2 );
	}
	bool compare ( node_type n, const wxString &str ) const 
	{
		return get_name ( n ) == str;
	}
	node_type invalid_node() const 
	{
		return 0;
	}
private:
	const wxString get_name ( node_type n ) const 
	{
		return n ? n->GetName() : empty_string;
	}
};

//! A tree adapther for the wxTreeItemId class.
template < typename node_type = wxTreeItemId >
class wxtreectrl_tree_adapter : public tree_adapter < node_type >
{
public:
	/*! @brief Constructor.
	 *
	 * @param ctrl The control that this tree adapter will use.
	 **/
	wxtreectrl_tree_adapter ( const wxTreeCtrl *ctrl ) : m_ctrl ( ctrl ) 
	{ 
	}
	const wxString get_content ( node_type n ) const 
	{
		return is_ok(n) ? m_ctrl->GetItemText(n) : empty_string;
	}
	node_type get_parent ( node_type n ) const 
	{
		return is_ok(n) ? m_ctrl->GetItemParent(n) : invalid_node();
	}
	node_type get_first_child ( node_type n ) 
	{
		return is_ok(n) ? m_ctrl->GetFirstChild ( n, m_cookie ) : invalid_node();
	}
	node_type get_next_sibling ( node_type n ) const 
	{
		return is_ok(n) ? m_ctrl->GetNextSibling(n) : invalid_node();
	}
	bool is_ok ( node_type n ) const 
	{
		return n.IsOk();
	}
	bool is_same_as ( node_type n1, node_type n2 ) const 
	{
		return n1 == n2;
	}
	bool compare ( node_type n, const wxString &str ) const 
	{
		return get_content(n) == str;
	}
	node_type invalid_node() const 
	{
		return wxTreeItemId();
	}
private:
	//! This 'cookie' is required by wxWidgets.
	wxTreeItemIdValue m_cookie;
	const wxTreeCtrl *m_ctrl;
};

/*! @brief A function to traverse every node in a tree.
 *
 * @param root The root node from which the traversing starts.
 * @param ta The tree adapter.
 * @parm f The function which will be called for every node (including the root).
 **/
template < typename node_type, typename func >
void traverse ( node_type root, tree_adapter < node_type > &ta, func f )
{
	f ( root );

	node_type node = ta.get_first_child ( root );

	while ( ta.is_ok ( node ) && !ta.is_same_as ( node, root ) )
	{
		f ( node );

		if ( ta.is_ok ( ta.get_first_child ( node ) ) )
		{
			node = ta.get_first_child ( node );
		}
		else
		{
			while ( !ta.is_ok ( ta.get_next_sibling ( node ) ) && 
				!ta.is_same_as ( node, root ) )
			{
				node = ta.get_parent ( node );
			}
			node = ta.get_next_sibling ( node );
		}
	}
}

//! A functor which compares a node to a string.
template < typename node_type, typename result_container = std::deque < node_type > >
class default_node_compare : public std::unary_function < node_type, void >
{
public:
	/*! @brief Constructor.
	 *
	 * @param str_cmp The string to which the node will be compared.
	 * @param results The container that will be used to push the node on
	 *                a positive match.
	 * @param ta The tree adapter.
	 **/
	default_node_compare ( const wxString &str_cmp, result_container &results,
		tree_adapter < node_type > &ta ) : mr_results ( results ), mr_ta ( ta ), 
		m_str_cmp ( str_cmp ) 
	{ 
	}
	void operator() ( node_type n ) 
	{ 
		if ( mr_ta.compare ( n, m_str_cmp ) ) mr_results.push_back(n);
	}
private:
	const wxString m_str_cmp;
	result_container &mr_results;
	const tree_adapter < node_type > &mr_ta;
};

/*! @brief Searches child nodes from the root node.
 *
 * Finds all nodes that are the same (i.e. the same name or the same
 * content (depending on the node type)) as 'str_cmp'.
 * 
 * @param str_cmp The string that will be used to compare against the node.
 * @param root The root node from which the search will start.
 * @param to The container that will hold the found nodes.
 * @param ta The tree adapter.
 * @return The number of nodes found.
 **/

template < typename node_type >
size_t search_nodes ( const wxString &str_cmp, node_type root, 
					 std::deque < node_type > &to, tree_adapter < node_type > &ta )
{
	traverse ( root, ta, default_node_compare < node_type > ( str_cmp, to, ta ) );
	return to.size();
}

/*! @brief Same as search_nodes but only returns the first found node.
 *
 * TODO: How-to make it so that the traversing stops after the first match 
 * has been found?
 **/
template < typename node_type >
node_type find_first_child_node ( const wxString &name, node_type root, 
								 tree_adapter < node_type > &ta )
{
	std::deque < node_type > ret;
	
	if ( search_nodes < node_type > ( name, root, ret, ta ) != 0 )
	{
		return ret.front();
	}
	return ta.invalid_node();
}

namespace gui 
{

//! A generic value getter for controls such as wxTextCtrl, wxComboBox, wxSpinCtrl etc.
const wxString get_ctrl_value ( long ctrl_id, long parent_id );

//! A specialized value getter for the wxPropertyGrid control.
const wxString get_prop_grid_value ( long ctrl_id, long parent_id,
									   const wxString &name );
//! A generic value setter for controls such as wxTextCtrl, wxComboBox, wxSpinCtrl etc.
void set_ctrl_value ( long ctrl_id, long parent_id, const wxString &val );

wxWindow *find_window ( long id, long parent_id );

}

}